package rpg.oop;

import acm.program.ConsoleProgram;
import acm.util.RandomGenerator;
import engine.Place;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Scanner;

public class RPG extends ConsoleProgram {
    public static final RandomGenerator randomGenerator = RandomGenerator.getInstance();
    Player player = new Player();
    Enemy enemy = new Enemy();
    GoldShop goldShop = new GoldShop();
    public final String GAME_FILE = "res/map-with-item.txt";
    boolean gameEnded;          // 玩家是否退出游戏
    int nPlaces;
    String goods;//地点总数量
    ArrayList<Place> places = new ArrayList<>();       // 保存所有的地点
    ArrayList<String> props = new ArrayList<>();      // 保存地图上所有的道具
    int baggageNum = 0;             //行李里的道具数量
    public Place currPlace;        // 当前所处的地点

    public void run() {
        println("-----------------------------------------------------------------------------\n" +
                "    __   _______            _  ________  __   _______ _   _  _____ \n" +
                "    \\ \\ / /_   _|   /\\     | |/ /  ____| \\ \\ / /_   _| \\ | |/ ____|\n" +
                "     \\ V /  | |    /  \\    | ' /| |__     \\ V /  | | |  \\| | |  __ \n" +
                "      > <   | |   / /\\ \\   |  < |  __|     > <   | | | . ` | | |_ |\n" +
                "     / . \\ _| |_ / ____ \\  | . \\| |____   / . \\ _| |_| |\\  | |__| |\n" +
                "    /_/ \\_\\_____/_/    \\_\\ |_|\\_\\______| /_/ \\_\\_____|_| \\_|\\_____|\n" +
                "                                                                                                                                                                                                                             \n" +
                "            ___     ____    . .     . .    _  |                                  \n" +
                "           __|__   `|_|_   -|-|-   .|_|_   L|-|-                     __         \n" +
                "            / \\    `|=|=   _|_|_   || |    L|`|             _--\\__ -   \\__/         \n" +
                "           /   \\   /j_|_   /   \\   ---`-      J             |         \\       \n" +
                "                                                           /   |       |      \n" +
                "                                                          |   |         |      \n" +
                "                                                    _/ \\_/    |                \n" +
                "   ________________O___o__._______________________/______/   |       --  _      \n" +
                "              ----- --------------------  -  ---        \\_ /       /            \n" +
                "                 ------- -----------   -  -                \\ --  /              \n" +
                "                      _ ______  _  __                            ---  _____     \n" +
                "                                                                                \n" +
                "                          ___ _                                                   \n" +
                "                                                                                \n" +
                "                       __  ___                _____  ___  ____             \n" +
                "               ___________  _________        ___                           \n" +
                "            ___    _____    ______  ______                                 \n" +
                "shi      __  ___   ______   __                                            \n" +
                "bu sh      ______   _  __    _______   _____                               \n" +
                "ay ir __    _________         ________   _                                 \n" +
                "enqi   an li    ___    ______     ______ ADA                                  \n" +
                "bu li  ux in      _______    __  ___    LA BA __                           \n" +
                "sh il  ia of    ____  _______   ____    YU      DO OG  DON    GYU   D ON                           \n" +
                "uyiq   us he          ____  __          SHUJI   EHA   OS HU  JI EH  AO SH                           \n" +
                "        ncan                            ZH UC   HE    NYUZH  UCHEN  YU ZH\n" +
                "          gg                            CA OL   IE    CA     OL     IE CA \n" +
                "        yum                              HUAN   MI     NJI    AHU   AN GM \n" +
                "------------------------------------------------------------------------------      ");
        println("");
        println("\"请点击右上角，全屏体验更加哦！\"—by Green");
        println("");
        println("序章：你正在执行门派给你分派的任务，打算做完这次就回去向师傅提亲迎娶小师妹，但是一夜之间你所在的" +
                "小门派惨遭屠戮，当你回到宗门的时候，尸横遍野，小师妹无影无踪。正当你不知发生什么的时候，你看到了一封" +
                "武林盟主威震天给你师傅写的一封信，内容似乎和武林秘籍有关，恰逢第21届武林大会，你发现此次大会的胜者奖品" +
                "居然就是信封中讨论的秘籍，你打算前往参加此次大会。");
        setupPlayer();
        if (loadGame()) {
            mainLoop();
        }
        if (!isPlayerDead()) {
            println("恭喜你！通关了！");
            println("你击败了师傅，武林恢复了平静，之后你和小师妹一起归隐山林，不再过问世事。");
        } else {
            println("。。。。。。。");
        }
    }

    /**
     * 移动到一个新的地点
     *
     * @param place 要移动到的目的地
     */
    private void moveTo(Place place) {
        println("你现在到了" + place.getName());
        currPlace = place;
        println(currPlace.getMessage());
        if (place.getProp() != null){
            println("这里有一个" + place.getProp());
        }

    }

    /**
     * 请玩家选择名字和角色，并初始化玩家的各种属性
     */
    private void setupPlayer() {
        print("请输入你的名字：");
        player.name = readLine();
        player.role = choose("请选择角色", "刀客", "剑客", "毒师");
        println("");
        player.level = 1;
        player.initialize(player);
    }

    /**
     * 主循环。只要玩家不选择退出，游戏就一直运行下去
     */
    private void mainLoop() {
        gameEnded = false;
        moveTo(currPlace);
        while (!gameEnded) {
            enemy.initialize(player);
            placeEnemy();
            println();
            println("请输入移动方向‘东南西北’（输入“查看地图”进入地图；输入“查看商店”进入商店；输入“搜索”获取当前地点的道具；输入“查看背包”查看道具" +
                    "输入\"退出\"结束游戏）");
            print("> ");

            String direction = readLine();
            if (currPlace.getName() != "炼狱魔窟"){
                switch (direction) {
                    case "东":
                        if (currPlace.getEast() != null) {
                            moveTo(currPlace.getEast());
                        } else {
                            println("那边好像无路可走了……");
                        }
                        break;
                    case "南":
                        if (currPlace.getSouth() != null) {
                            moveTo(currPlace.getSouth());
                        } else {
                            println("那边好像无路可走了……");
                        }
                        break;
                    case "西":
                        if (currPlace.getWest() != null) {
                            moveTo(currPlace.getWest());
                        } else {
                            println("那边好像无路可走了……");
                        }
                        break;
                    case "北":
                        if (currPlace.getNorth() != null) {
                            moveTo(currPlace.getNorth());
                        } else {
                            println("那边好像无路可走了……");
                        }
                        break;
                    case "搜索":
                        if (currPlace.getProp() != null) {
                            pickProps(currPlace);
                        }
                        break;
                    case "查看财富":
                        printGold();
                        break;
                    case "查看背包":
                        checkBaggageNum();
                        checkBaggage();
                        break;
                    case "查看商店":
                        ArrayList<String> list1 = GoldShop.shopList();
                        for (int i = 0; i < list1.size(); i++) {
                            println(list1.get(i));
                        }
                        println();
                        println("输入购买对象购买商品或者输入退出离开商店");
                        println(">");
                        String a = readLine();
                        if (a.equals("退出")) {
                            return;
                        } else if (a.equals("九阳神功") || a.equals("九阴白骨爪")) {
                            if (GoldShop.gold >= 35) {
                                goods = a;
                                GoldShop.shopList();
                                println("购买成功");
                            } else {
                                println("购买失败，金额不足");
                            }
                        } else if (a.equals("精钢剑") || a.equals("百炼刀") || a.equals("青铜鼎")) {
                            if (GoldShop.gold >= 20) {
                                goods = a;
                                GoldShop.shopList();
                                println("购买成功");
                            } else {
                                println("购买失败，金额不足");
                            }
                        } else if (a.equals("伸腿瞪眼丸") || a.equals("柴刀") || a.equals("铁剑")) {
                            if (GoldShop.gold >= 10) {
                                goods = a;
                                GoldShop.shopList();
                                println("购买成功");
                            } else {
                                println("购买失败，金额不足");
                            }
                        }
                        break;


                    case "查看地图":
                        println("                     天河派\n" +
                                "                       |\n" +
                                "             瀑布 ————浮水桥——————— 玹剑门                     \n" +
                                "                        |             | \n" +
                                " 终南山顶——竹间小苑 —— 天水城————天水集市 —— 天魁武馆    \n" +
                                "                       |\n" +
                                "                    侠客岛             \n" +
                                "                     |\n" +
                                "                    扶风谷                           \n" +
                                "                        |     \n" +
                                "海上明月 —— 火幽离原—— 沙梦河 ———— 邛崃 ———— 天上人间             \n" +
                                "    |                  |           ||      \t           \n" +
                                "  不周滩             子午路         ||   \n" +
                                "    |                 |            ||    \n" +
                                "百花深处—————巫溪————风阙           ||\n" +
                                "                      |            ||               \n" +
                                "                    当归路 ———————云梦泽\n" +
                                "                      |\n" +
                                "                   勒马听风\n" +
                                "                      |\n" +
                                "                    姑苏\n" +
                                "                      |\n" +
                                "                      |  \n" +
                                "                   炼狱魔窟");
                        break;


                    case "退出":
                        gameEnded = true;
                        println("欢迎再来！");
                        break;
                    default:
                        println("你输入的命令有误，请重新输入");
                }
            }
        }
    }

    private void printGold() {
        String message = String.format("当前有%d金币，有%d声望值", GoldShop.getGold(enemy), GoldShop.getReputation(enemy));
        println(message);
    }

    /**
     * 进入/触发一个新的游戏场景
     *
     * @param scene 游戏场景名称
     */
    private void playScene(String scene) {
        // 每个场景随机产生1-3个敌人
        int enemyCount = randomGenerator.nextInt(1, 9);
        for (int i = 0; i < 1; i++) {
            if (isPlayerDead()) {
                println("胜败乃兵家常事，大侠请重新来过。");
                break;
            }
            enemy.initialize(player);
            println();
            println("你遇到了" + enemy.role + enemy.name + "。");
            battle();
        }
    }

    /**
     * 玩家和敌人对战
     */
    public void battle() {
        printPlayerStatus();
        printEnemyStatus();

        // 回合制循环进行，直至某一方阵亡
        while (true) {
            println();

            // 每一回合都首先从玩家开始行动
            String userChoice = choose("请选择你的行动", "一剑", "隔日再战", "回复血量", "查看当前状态" );
            if (userChoice.equals("查看当前状态")) {
                printPlayerStatus();
                continue;
            } else if (userChoice.equals("回复血量")) {
                useHealthPotion();
                printPlayerStatus();
                continue;
            } else if (userChoice.equals("隔日再战")) {
                boolean success = randomGenerator.nextBoolean();
                if (success) {
                    println("不讲武德！");
                    break;
                } else {
                    println("穷寇莫追！");
                }
            } else if (userChoice.equals("一剑")) {
                attackEnemy();
                printEnemyStatus();
            }

            if (enemy.isEnemyDead()) {
                // 如果敌人阵亡，玩家经验值提升
                println(String.format("你战胜了%s。\n", enemy.name));
                println("你获取了" + player.gainXp(enemy) + "点经验值。");
                println("你拥取了" + GoldShop.getReputation(enemy) + "点声望");
                println("你得到了" + GoldShop.getGold(enemy) + "的金币");
                if (player.checkLevelUp()) {
                    println("你升级了！武学境界得到了提升！");
                }
                println("你当前拥有" + player.xp + "点经验值。");
                println("你当前拥有" + GoldShop.reputation + "的声望");
                println("你当前获取" + GoldShop.gold + "的金币");
                printPlayerStatus();
                break;
            } else {
                // 没阵亡则轮到敌人行动
                attackPlayer();
                printPlayerStatus();
                if (isPlayerDead()) {
                    println("你开始视线模糊，你似乎又看到了宗门的练武场，过去的忆往开始如走马灯一样，你最终意识到自己还是太弱了！");
                    println("江湖险恶，谨慎前行！");
                }
            }
        }
    }

    // 如果敌人将玩家打死，游戏结束
//            if (isPlayerDead()) {
//                println();
//                println("请选择是否复活（是/否）");
//                String life = readLine();
//                switch (life) {
//                    case "是":
//                            GoldShop.resurgence();
//                            break;
//                    case "否":
//                        println("你开始视线模糊，你似乎又看到了宗门的练武场，过去的忆往开始如走马灯一样，你最终意识到自己还是太弱了！");
//                        println("江湖险恶，谨慎前行！");
//                        break;
//                    default:
//                        println("你输入的命令有误，请重新输入");
//                }
//            }


    //确认这个地方是否有敌人
    public void placeEnemy() {
        String isEnemy = currPlace.getName();
        switch (isEnemy) {
            case "终南山顶":
                playScene("终南山顶");
                break;
            case "玹剑门":
                playScene("玹剑门");
                break;
            case "天魁武馆":
                playScene("天魁武馆");
                break;
            case "海上明月":
                playScene("海上明月");
                break;
            case "天上人间":
                playScene("天上人间");
                break;
            case "百花深处":
                playScene("百花深处");
                break;
            case "风阙":
                playScene("风阙");
                break;
            case "勒马听风":
                playScene("勒马听风");
                break;
            case "炼狱魔窟":
                if (enemy.level < 8){
                    println("前方终极boss，请升到8级后再来。");
                }else{
                    playScene("炼狱魔窟");
                }
                break;
            default:
                break;
        }
    }


    /**
     * 玩家攻击敌人
     */
    private void attackEnemy() {
        // 对敌人造成的真实伤害是玩家攻击力下限和上限之间的一个随机数
        int damage = randomGenerator.nextInt(player.minAtt, player.maxAtt);
        enemy.curHp -= damage;
        println(String.format("%s对%s造成%d点伤害。", player.name, enemy.name, damage));
    }

    /**
     * 敌人攻击玩家
     */
    private void attackPlayer() {
        // 敌人对玩家造成的真实伤害是敌人攻击力下限和上限之间的一个随机数
        int damage = randomGenerator.nextInt(enemy.minAtt, enemy.maxAtt);
        player.curHp -= damage;
        println(String.format("%s对%s造成%d点伤害。", enemy.name, player.name, damage));
    }

    /**
     * 使用补血药剂，可以补血25。
     */
    private void useHealthPotion() {
        if (player.hpPotions > 0) {
            int hpIncreased = 25;
            if (hpIncreased > (player.maxHp - player.curHp)) {
                hpIncreased = player.maxHp - player.curHp;
            }
            player.curHp += hpIncreased;
            player.hpPotions--;
            println(String.format("成功回血%d。当前血量%d, 还剩%d瓶回血药。", hpIncreased, player.curHp, player.hpPotions));
        } else {
            println("回血失败：回血药已用完。");
        }
    }

    /**
     * 打印敌人状态：名字，当前血量
     */
    private void printEnemyStatus() {
        String message = String.format("%s当前血量%d/%d,等级为%d,职业为%s", enemy.name, enemy.curHp, enemy.maxHp, enemy.level, enemy.role);
        println(message);

    }

    /**
     * 打印玩家状态：名字，当前血量
     */
    private void printPlayerStatus() {
        String message = String.format("%s当前血量%d/%d，等级为%d,职业为%s", player.name, player.curHp, player.maxHp, player.level, player.role);
        println(message);

    }

    /**
     * 判断玩家是否已经死亡
     *
     * @return 死亡返回true，未死亡返回false
     */
    private boolean isPlayerDead() {
        return player.curHp <= 0;
    }

    /**
     * 判断敌人是否已经死亡
     *
     * @return 死亡返回true，未死亡返回false
     */
    private boolean isEnemyDead() {
        return enemy.curHp <= 0;
    }


    /**
     * 提示用户做选择，如果用户的选择无效，就让用户重新输入
     *
     * @param prompt  提示语
     * @param choices 允许的几种选择
     * @return 玩家最终的选择
     */
    public final String choose(String prompt, String... choices) {
        // 将选择用逗号连起来
        String concatenatedChoices = String.join(", ", choices);
        // 最终的提示语
        String actualPrompt = String.format("%s (%s): ", prompt, concatenatedChoices);

        // 如果玩家的输入无效，就提示玩家重新输入
        while (true) {
            print(actualPrompt);
            String userChoice = readLine();

            // 逐个对比，看是否相等
            for (String choice : choices) {
                if (userChoice.equals(choice)) {
                    return choice;
                }
            }
            println("您的选择无效，请重新输入。");
        }
    }

    /**
     * 读取游戏配置，如地图等
     *
     * @return 读取成功返回true，失败返回false
     */
    private boolean loadGame() {
        places = new ArrayList<>();
        try {
            Scanner scanner = new Scanner(new File(GAME_FILE));
            loadPlaces(scanner);
            loadRoutes(scanner);
            loadProps(scanner);
        } catch (FileNotFoundException e) {
            println("游戏文件读取错误！");
            return false;
        }
        return true;
    }

    //加载路线
    public void loadRoutes(Scanner scanner) {
        int nRoutes = scanner.nextInt();
        scanner.next();
        for (int i = 0; i < nRoutes; i++) {
            int placeName1 = scanner.nextInt();
            String direction = scanner.next();
            int placeName2 = scanner.nextInt();
            for (int j = 0; j < nPlaces; j++) {
                if (placeName1 == (places.get(j).getId())) {
                    for (int k = 0; k < nPlaces; k++) {
                        if (placeName2 == (places.get(k).getId())) {
                            switch (direction) {
                                case ("东"):
                                    places.get(j).setEast(places.get(k));
                                    places.get(k).setWest(places.get(j));
                                    break;
                                case ("西"):
                                    places.get(j).setWest(places.get(k));
                                    places.get(k).setEast(places.get(j));
                                    break;
                                case ("南"):
                                    places.get(j).setSouth(places.get(k));
                                    places.get(k).setNorth(places.get(j));
                                    break;
                                case ("北"):
                                    places.get(j).setNorth(places.get(k));
                                    places.get(k).setSouth(places.get(j));
                                    break;
                            }
                        }
                    }
                }
            }
        }
    }

    /**
     * 读取地点
     *
     * @param scanner 用来读取输入的scanner对象
     */
    public void loadPlaces(Scanner scanner) {
        // 读取地点
        nPlaces = scanner.nextInt();            // 地点的数量
//        message = new String[nPlaces];
        scanner.next();
        // 读取所有地点
        for (int i = 0; i < nPlaces; i++) {
            int id = scanner.nextInt();       //地点的编号
            String placeName = scanner.next();// 地点的名称
            String messageName = scanner.next();//信息

            Place place = new Place(placeName);     // 从Place类别中创建一个实例，并
            places.add(place);                      // 将这个地点保存进places中
            place.setMessage(messageName);
            place.setId(id);
        }

        // 设置初始地点，也就是读进来的第一个地点
        currPlace = places.get(0);
    }

    //加载地图上的道具
    public void loadProps(Scanner scanner) {
        int nProps = scanner.nextInt();            //道具的数量
        scanner.next();
        for (int i = 0; i < nProps; i++) {
            int id = scanner.nextInt();
            String prop = scanner.next();
            places.get(id).setProp(prop);
            props.add(prop);
        }
    }

    //获取当前位置的道具
    public void pickProps(Place place) {

        baggageNum += 1;
        println ("你找到了一个" + place.getProp() + "！");
        place.setProp(null);
    }

    //查看背包道具数量
    public void checkBaggageNum() {
        if (baggageNum != 0) {
            println (String.format("你现在共有%d个道具，依次是：", baggageNum));
        } else {
            println ("你的行李箱内空无一物。");
        }
    }

    // 查看背包
    public void checkBaggage() {
        String j = "";                          //返回的语句
        if (baggageNum != 0) {
            for (int i = 0; i < baggageNum; i++) {
                j = j + String.format("%d.%s", i + 1, props.get(i));
            }
        }
        println(j);
    }

    //获取当前位置
    public Place getCurrPlace() {
        return currPlace;
    }

    //设置当前位置
    public void setCurrPlace(Place currPlace) {
        this.currPlace = currPlace;
    }

    /**
     * 商店道具
     */
    public void buyGoods() {
        int attackMaxIncrease = 0;
        int hpMaxIncrease = 0;
        switch (goods) {
            case "九阳神功":
                hpMaxIncrease = 10;
                GoldShop.gold -= 35;
                goods = "九阳神功";
                break;
            case "九阴白骨爪":
                attackMaxIncrease = 9;
                GoldShop.gold -= 35;
                goods = "九阴白骨爪";
                break;
            case "铁剑":
                attackMaxIncrease = 10;
                GoldShop.gold -= 10;
                goods = "铁剑";
                break;
            case "精钢剑":
                attackMaxIncrease = 17;
                GoldShop.gold -= 20;
                goods = "精钢剑";
                break;
            case "柴刀":
                attackMaxIncrease = 11;
                GoldShop.gold -= 10;
                goods = "柴刀";
                break;
            case "百炼刀":
                attackMaxIncrease = 16;
                GoldShop.gold -= 20;
                goods = "百炼刀";
                break;
            case "炼毒罐":
                attackMaxIncrease = 12;
                GoldShop.gold -= 10;
                goods = "炼毒罐";
                break;
            case "青铜鼎":
                attackMaxIncrease = 15;
                GoldShop.gold -= 20;
                goods = "青铜鼎";
                break;
            case "伸腿瞪眼丸":
                player.hpPotions++;
                GoldShop.gold -= 10;
                goods = "伸腿瞪眼丸";
                break;
        }
        player.maxHp = randomGenerator.nextInt(1, 6) + player.curHp;
        player.curHp = player.maxHp;
        player.maxAtt += randomGenerator.nextInt(0, attackMaxIncrease);
        player.minAtt = player.maxAtt - 3;
    }
}
